#include "DesktopPictureFrame.h"


DesktopPictureFrame::DesktopPictureFrame()
{	
	imageRatio = 0;
	image = 0;
	sizing  = false;
	imageOffset = 8;

	SetPicture(TEXT("picture.jpg"), false);	
}


DesktopPictureFrame::~DesktopPictureFrame()
{
	Settings s;
	Settings::Data data={0};
	s.Load(&data);
	data.DesktopPictureFrameData.Bounds = this->GetBounds();
	s.Save(data);

    Deactivate();

	if (image)
	{
		delete image;
		image = 0;
	}
}

void DesktopPictureFrame::Create(HINSTANCE hInstance)
{
	BOOL dwmEnabled;
	DwmIsCompositionEnabled(&dwmEnabled);	

	if (!dwmEnabled)
		imageOffset = 0;

	CustomWindow::Create(hInstance,
						TEXT("DesktopPictureFrame"),
						WndProc,
						WS_EX_TOOLWINDOW,
						!dwmEnabled ? WS_POPUP | WS_THICKFRAME : WS_THICKFRAME,
						CS_NOCLOSE | CS_VREDRAW | CS_HREDRAW,
						GetStockBrush(BLACK_BRUSH));

	this->SetFrameMargins(8, 8, 8, 8);
	this->SetLocation(0, 0);

	if (image)
	{
		this->SetGlassMargins(8, 8, 8, 8);
		this->SetSize(image->GetWidth() / 3, image->GetHeight() / 3);
	}

	else
	{
		this->SetGlassMargins(-1, -1, -1, -1);
		this->SetSize(150, 150);
	}

	Settings s;
	Settings::Data data={0};
	data.DesktopPictureFrameData.Bounds = this->GetBounds();
	s.Load(&data);

	this->SetBounds(data.DesktopPictureFrameData.Bounds);

	BOOL bl=TRUE;
	DwmSetWindowAttribute(this->GetHWnd(),DWMWA_DISALLOW_PEEK,&bl, sizeof(bl));
	DwmSetWindowAttribute(this->GetHWnd(),DWMWA_EXCLUDED_FROM_PEEK,&bl, sizeof(bl));

	DWMFLIP3DWINDOWPOLICY flip3DPolicy = DWMFLIP3D_EXCLUDEBELOW;
	DwmSetWindowAttribute(this->GetHWnd(), DWMWA_FLIP3D_POLICY, &flip3DPolicy, sizeof(DWMWA_FLIP3D_POLICY));
}


CCState DesktopPictureFrame::Activate()
{
    CCState result;
    if ((result = CassiopeiaComponent::Activate()) != CCState::Successful)
        return result;
	
    Utilities::MoveWindowIntoVisibleArea(this->GetHWnd());
   
    this->ShowNoActivate();
    SetWindowPos(this->GetHWnd(), Utilities::GetLastValidTopLevelWindow(), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
	
    return CCState::Successful;
}

CCState DesktopPictureFrame::Deactivate()
{
    CCState result;
    if ((result = CassiopeiaComponent::Deactivate()) != CCState::Successful)
        return result;

    this->Hide();

    return CCState::Successful;
}


void DesktopPictureFrame::SetPicture(tstring fileName, bool copy)
{
	if (image)
	{
		delete image;
		image = 0;
	}

	if (!Utilities::ExistsFile(fileName))
		return;

	if (copy && !CopyPicture(fileName, TEXT("picture.jpg")))
		return;

	image = Image::FromFile(TEXT("picture.jpg"));

	if (image->GetLastStatus() != Gdiplus::Status::Ok)
	{
		delete image;
		image = 0;
		return;
	}		

	imageRatio = (double)((double)image->GetWidth() / (double)image->GetHeight());
	this->SetGlassMargins(8, 8, 8, 8);
	this->SetSize(image->GetWidth() / 3, image->GetHeight() / 3);
	InvalidateRgn(this->GetHWnd(), 0, TRUE);
}


bool DesktopPictureFrame::CopyPicture(tstring fileName, tstring copyFileName)
{
	if (!Utilities::ExistsFile(fileName))
		return false;

	Image* tmpImage = Image::FromFile(fileName.c_str());

	if (tmpImage->GetLastStatus() != Gdiplus::Status::Ok)
	{
		delete tmpImage;
		tmpImage = 0;
		return false;
	}		

	CLSID pngClsid;
	Utilities::GetEncoderClsid(TEXT("image/jpeg"), &pngClsid);
	

	bool result;

	if (tmpImage->Save(copyFileName.c_str(), &pngClsid, 0) != Gdiplus::Status::Ok)
		result = false;
	else
		result = true;

	delete tmpImage;
	tmpImage = 0;

	return result;
}

HRESULT DesktopPictureFrame::ShowOpenFileDialog(HWND hwnd, LPTSTR * fileName)
{
    HRESULT hr = CoInitialize(0);

    if (SUCCEEDED(hr))
    {
        IFileDialog *fileDialog;
        
        hr = CoCreateInstance(CLSID_FileOpenDialog, 
                                      0, 
                                      CLSCTX_INPROC_SERVER, 
                                      IID_PPV_ARGS(&fileDialog));
        
        if (SUCCEEDED(hr))
        {
			COMDLG_FILTERSPEC aFileTypes[] = {
				{L"Image files", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif"},
				{L"JPEG files", L"*.jpg;*.jpeg"},
				{L"PNG files", L"*.png"},
				{L"Bitmap files", L"*.bmp"},
				{L"GIF", L"*.gif"}
			};

			fileDialog->SetFileTypes(_countof(aFileTypes), aFileTypes);

            hr = fileDialog->Show(hwnd);
            
            if (SUCCEEDED(hr))
            {
                IShellItem *result;
                hr = fileDialog->GetResult(&result);

                if (SUCCEEDED(hr))
                {
                    result->GetDisplayName(SIGDN_FILESYSPATH, fileName);
                    result->Release();
                }
            }
            fileDialog->Release();
        }
    }

    CoUninitialize();

    return hr;
}



LRESULT CALLBACK DesktopPictureFrame::WndProc(LPVOID sender, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{	
	DesktopPictureFrame* instance = (DesktopPictureFrame*)((CustomWindow*)sender);

	switch (uMsg)
	{
	case WM_LBUTTONDOWN:
		{
			SendMessage(hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
			break;
		}
	case WM_ACTIVATE:
		{
			if (wParam == WA_INACTIVE)
				SetWindowPos(hWnd, Utilities::GetLastValidTopLevelWindow(), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
			break;
		}
	case WM_PAINT:
		{
			if (instance->sizing || !instance->image)
				break;

			HDC          hdc;
            PAINTSTRUCT  ps;

            hdc = BeginPaint(hWnd, &ps);

			RECT clientRect;
            GetClientRect(hWnd, &clientRect);	
			
			Graphics g(hdc);
			g.DrawImage(instance->image, instance->imageOffset, instance->imageOffset, RECTWIDTH(clientRect) - instance->imageOffset * 2, RECTHEIGHT(clientRect) - instance->imageOffset * 2); 

			EndPaint(hWnd, &ps);

			break;
		}
	case WM_ENTERSIZEMOVE:
		{
			GetWindowRect(hWnd, &instance->sizingRect);
			break;
		}
	case WM_SIZING:
		{
			if (!instance->imageRatio)
				break;

			RECT* rect = (RECT*)lParam;
				
			//keep aspect ratio
			if (wParam == WMSZ_BOTTOM || wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT)
				rect->right = rect->left + (int)((double)(PRECTHEIGHT(rect)) * instance->imageRatio);
			
			else if (wParam == WMSZ_RIGHT || wParam == WMSZ_LEFT || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT)
				rect->bottom = rect->top + (int)((double)(PRECTWIDTH(rect)) * (1 / instance->imageRatio));
			
			else if (wParam == WMSZ_TOPLEFT)
				rect->left = rect->right - (int)((double)(PRECTHEIGHT(rect)) * instance->imageRatio);

			if (!instance->sizing)
			{
				instance->sizing = true;
				instance->SetGlassMargins(-1, -1, -1, -1);
				InvalidateRgn(hWnd, 0, TRUE);
			}
			
			break;
		}
	case WM_EXITSIZEMOVE:
		{
			if (instance->sizing)
			{
				instance->sizing = false;
				InvalidateRgn(hWnd, 0, TRUE);
				instance->SetGlassMargins(8, 8, 8, 8);
			}

			break;
		}
	case WM_GETMINMAXINFO:
		{
			MINMAXINFO * mmi = (MINMAXINFO*)lParam;
			mmi->ptMinTrackSize.x = 60;
			mmi->ptMinTrackSize.y = 60;
			
			return S_OK;
		}
	case WM_CONTEXTMENU:
		{
			POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

			HMENU hMenu = CreatePopupMenu();
			AppendMenu(hMenu, MF_STRING, 1, Translate(2, TEXT("Set Picture"), TEXT("#...")).c_str());

			SetForegroundWindow(hWnd);


			if (mousePos.x == -1 && mousePos.y == -1)
			{	
				POINT pos = {instance->GetLocation().x + instance->GetSize().cx / 2, instance->GetLocation().y + instance->GetSize().cy / 2};
				TrackPopupMenu(hMenu, TPM_VERNEGANIMATION | TPM_LEFTBUTTON, pos.x, pos.y, 0, hWnd, 0);
			}
			else
			{
				TrackPopupMenu(hMenu, TPM_VERNEGANIMATION | TPM_LEFTBUTTON, mousePos.x, mousePos.y, 0, hWnd, 0);
			}

			PostMessage(hWnd, WM_NULL, 0, 0);

			break;
		}
	case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
			case 1:
				{
					LPTSTR fileName;
					HRESULT hr = instance->ShowOpenFileDialog(hWnd, &fileName);	

					if (SUCCEEDED(hr))
						instance->SetPicture(fileName, true);

					break;
				}
			}

			break;
		}
	case WM_DWMCOMPOSITIONCHANGED:
		{
			BOOL dwmEnabled;
			DwmIsCompositionEnabled(&dwmEnabled);	

			if (!dwmEnabled)
			{			
				instance->imageOffset = 0;
				SetWindowLongPtr(hWnd, GWL_STYLE, GetWindowLongPtr(hWnd, GWL_STYLE) | WS_POPUP);
				SetWindowLongPtr(hWnd, GWL_STYLE, GetWindowLongPtr(hWnd, GWL_STYLE) & ~WS_CAPTION);
			}
			else
			{
				instance->imageOffset = 8;
				SetWindowLongPtr(hWnd, GWL_STYLE, GetWindowLongPtr(hWnd, GWL_STYLE) & ~WS_POPUP);
				SetWindowLongPtr(hWnd, GWL_STYLE, GetWindowLongPtr(hWnd, GWL_STYLE) | WS_CAPTION);
			}

			InvalidateRgn(hWnd, 0, true);
			break;
		}
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
